﻿using Hotel.Domain;
using Hotel.Domain.Audit.Implementation;
using Hotel.Domain.Audit.Interfaces;
using Hotel.Utility;
using IdentityModel;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.FileIO;
using SqlSugar;
using SqlSugar.Extensions;
using System.Linq.Expressions;
using static System.Net.WebRequestMethods;

namespace Hotel.Repositories
{
    public class Repository<TEntity> : IRepository<TEntity>
        where TEntity : class, new()
    {
        private readonly ISqlSugarClient db;

        public Repository(ISqlSugarClient db)
        {
            this.db = db;
        }

        public ILoggerFactory LoggerFactory { get; set; }

        public enum AuditFieldType
        {
            Create,
            LastModify, 
            Delete
        }

        /// <summary>
        /// 自动赋值
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="fieldType"></param>
        protected void AutoSetValue(TEntity entity, AuditFieldType fieldType)
        {
            try
            {
                var entityTypes = entity.GetType().GetProperties();
                var OperatorTime = entityTypes.FirstOrDefault(m => m.Name == $"{fieldType}Time");
                if (OperatorTime != null)
                {
                    OperatorTime.SetValue(entity, DateTime.Now);
                }

                //HttpContextAccessor http = new HttpContextAccessor();
                IHttpContextAccessor http = ServiceProviderInstance.Instance.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
                //判断是否登录，如果登录，创建人赋值
                if (http.HttpContext.User.Identity.IsAuthenticated)
                {
                    var OperatorByName = entityTypes.FirstOrDefault(m => m.Name == $"{fieldType}Name");
                    if (OperatorByName != null)
                    {
                        string name = http.HttpContext.User.Claims.FirstOrDefault(m => m.Type == JwtClaimTypes.Name).Value;
                        OperatorByName.SetValue(entity, name);
                    }

                    if(fieldType == AuditFieldType.LastModify)
                    {

                    }
                }
            }
            catch (Exception e)
            {
                ILoggerFactory loggerFactory = ServiceProviderInstance.Instance.GetService(typeof(ILoggerFactory)) as ILoggerFactory;

                ILogger logger = loggerFactory.CreateLogger(typeof(Repository<TEntity>));

                logger.LogError(e, e.Message);

                throw;
            }            
        }

        /// <summary>
        /// 同步添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual long Insert(TEntity entity)
        {
            AutoSetValue(entity, AuditFieldType.Create);
            return db.Insertable(entity).ExecuteReturnSnowflakeId();
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<long> InsertAsync(TEntity entity)
        {
            AutoSetValue(entity, AuditFieldType.Create);
            return await db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public virtual async Task<List<long>> ManyInsertAsync(List<TEntity> entities)
        {
            entities.ForEach(entity => {
                AutoSetValue(entity, AuditFieldType.Create);
            });
            return await db.Insertable(entities).ExecuteReturnSnowflakeIdListAsync();
        }

        private async Task<int> DeleteHandle(Expression<Func<TEntity, bool>> expression)
        {
            var entityTypes = typeof(TEntity).GetProperties();
            var OperatorTime = entityTypes.FirstOrDefault(m => m.Name == nameof(ISoftDelete.IsDeleted));
            if (OperatorTime != null)
            {
                IHttpContextAccessor http = ServiceProviderInstance.Instance.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
                //判断是否登录，如果登录，创建人赋值
                if (http.HttpContext.User.Identity.IsAuthenticated)
                {
                    //逻辑删除
                    return await
                    db.Deleteable<TEntity>().Where(expression).IsLogic().ExecuteCommandAsync(
                        LogicFieldName: nameof(ISoftDelete.IsDeleted),
                        deleteValue: true,
                        deleteTimeFieldName: nameof(FullAuditedEntity.DeleteTime),
                        userNameFieldName: nameof(FullAuditedEntity.DeleteName),
                        userNameValue: http.HttpContext.User.Identity.Name
                    );
                }
                throw new Exception();
            }
            else
            {
                return await db.Deleteable<TEntity>().Where(expression).ExecuteCommandAsync();
            }
        }

        /// <summary>
        /// 委托方式调用
        /// </summary>
        /// <param name="LogicDeleteMethod"></param>
        /// <param name="PhysicalDeleteMethod"></param>
        /// <returns></returns>
        private async Task<int> DeleteHandler(Func<string, object, string, string, object, Task<int>> LogicDeleteMethod, Func<Task<int>> PhysicalDeleteMethod)
        {
            var entityTypes = typeof(TEntity).GetProperties();
            var OperatorTime = entityTypes.FirstOrDefault(m => m.Name == nameof(ISoftDelete.IsDeleted));
            if (OperatorTime != null)
            {
                IHttpContextAccessor http = ServiceProviderInstance.Instance.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
                //逻辑删除
                return await
                LogicDeleteMethod(
                    nameof(ISoftDelete.IsDeleted),
                    true,
                    nameof(FullAuditedEntity.DeleteTime),
                    nameof(FullAuditedEntity.DeleteName),
                    http.HttpContext.User.Identity.Name
                );
            }
            else
            {
                return await PhysicalDeleteMethod();
            }
        }

        /// <summary>
        /// 单条根据主键删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> DeleteAsync(long key)
        {
            return await DeleteHandler(
                async (a, b, c, d, e) => {
                    return await db.Deleteable<TEntity>(key).IsLogic().ExecuteCommandAsync(a, b, c, d, e);
                }
                ,
                async () => {
                    return await db.Deleteable<TEntity>(key).ExecuteCommandAsync();
                }
            );
        }

        /// <summary>
        /// 单条根据实体删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> DeleteAsync(TEntity entity)
        {
            return await DeleteHandler(
                async (a, b, c, d, e) => {
                    return await db.Deleteable<TEntity>(entity).IsLogic().ExecuteCommandAsync(a, b, c, d, e);
                }
                , async () => {
                    return await db.Deleteable<TEntity>(entity).ExecuteCommandAsync();
                }
            );
        }

        /// <summary>
        /// 批量根据实体删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> DeleteAsync(List<TEntity> entities)
        {
            return await DeleteHandler(
                async (a, b, c, d, e) => {
                    return await db.Deleteable<TEntity>(entities).IsLogic().ExecuteCommandAsync(a, b, c, d, e);
                }
                , async () => {
                    return await db.Deleteable<TEntity>(entities).ExecuteCommandAsync();
                }
            );
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> ManyDeleteAsync(List<long> keys)
        {
            return await DeleteHandler(
                async (a, b, c, d, e) => {
                    return await db.Deleteable<TEntity>(keys).IsLogic().ExecuteCommandAsync(a, b, c, d, e);
                }
                , async () => {
                    return await db.Deleteable<TEntity>(keys).ExecuteCommandAsync();
                }
            );
        }

        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<int> DeleteAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await DeleteHandler(
                async (a, b, c, d, e) => {
                    return await db.Deleteable<TEntity>().Where(expression).IsLogic().ExecuteCommandAsync(a, b, c, d, e);
                }
                , async () => {
                    return await db.Deleteable<TEntity>().Where(expression).ExecuteCommandAsync();
                }
            );
        }

        /// <summary>
        /// 单条更新
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<int> UpdateAsyc(TEntity entity)
        {
            //更新末次修改时间，修改人
            AutoSetValue(entity, AuditFieldType.LastModify);
            return await db.Updateable(entity).IgnoreColumns
                (
                nameof(FullAuditedEntity.CreateName),
                nameof(FullAuditedEntity.CreateTime),
                nameof(FullAuditedEntity.DeleteName),
                nameof(FullAuditedEntity.DeleteTime),
                nameof(FullAuditedEntity.IsDeleted)
                ).ExecuteCommandAsync();
        }

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public virtual async Task<int> ManyUpdateAsyc(List<TEntity> entities)
        {
            entities.ForEach(entity => { 
                AutoSetValue(entity, AuditFieldType.LastModify);
            });
            return await db.Updateable(entities)
                .IgnoreColumns
                (
                nameof(FullAuditedEntity.CreateName),
                nameof(FullAuditedEntity.CreateTime),
                nameof(FullAuditedEntity.DeleteName),
                nameof(FullAuditedEntity.DeleteTime),
                nameof(FullAuditedEntity.IsDeleted)
                ).ExecuteCommandAsync();
        }

        /// <summary>
        /// 根据条件更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<int> UpdateAsyc(TEntity entity, Expression<Func<TEntity, bool>> expression)
        {
            AutoSetValue(entity, AuditFieldType.LastModify);
            return await db.Updateable<TEntity>(entity).IgnoreColumns
                (
                nameof(FullAuditedEntity.CreateName),
                nameof(FullAuditedEntity.CreateTime),
                nameof(FullAuditedEntity.DeleteName),
                nameof(FullAuditedEntity.DeleteTime),
                nameof(FullAuditedEntity.IsDeleted)
                ).Where(expression).ExecuteCommandAsync();
        }

        /// <summary>
        /// 单条更新并忽略某些字段
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<int> UpdateAsyc(TEntity entity,params string[] columns)
        {
            string[] IgnoreColumns = {
                nameof(FullAuditedEntity.CreateName),
                nameof(FullAuditedEntity.CreateTime),
                nameof(FullAuditedEntity.DeleteName),
                nameof(FullAuditedEntity.DeleteTime),
                nameof(FullAuditedEntity.IsDeleted)
            };

            //更新末次修改时间，修改人
            AutoSetValue(entity, AuditFieldType.LastModify);
            return await db.Updateable(entity).IgnoreColumns(IgnoreColumns.Concat(columns).ToArray()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 更新某些字段
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="columns">要更新的字段</param>
        /// <returns></returns>
        public virtual async Task<int> UpdateByFieldsAsyc(TEntity entity, params string[] columns)
        {
            string[] updateColumns = {
                nameof(FullAuditedEntity.LastModifyName),
                nameof(FullAuditedEntity.LastModifyTime)
            };
            AutoSetValue(entity, AuditFieldType.LastModify);
            return await db.Updateable<TEntity>(entity).UpdateColumns(updateColumns.Concat(columns).ToArray()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 根据条件更新某些字段
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="expression"></param>
        /// <param name="columns"></param>
        /// <returns></returns>
        public virtual async Task<int> UpdateAsyc(TEntity entity, Expression<Func<TEntity, bool>> expression, params string[] columns)
        {
            AutoSetValue(entity, AuditFieldType.LastModify);
            return await db.Updateable<TEntity>(entity).Where(expression).UpdateColumns(columns).ExecuteCommandAsync();
        }

        /// <summary>
        /// 根据主键查单条
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> FindAsync(long key)
        {
            return await db.Queryable<TEntity>().InSingleAsync(key);
        }

        /// <summary>
        /// 根据条件查单条
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await db.Queryable<TEntity>().SingleAsync(expression);
        }

        /// <summary>
        /// 根据主键查第一条
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await db.Queryable<TEntity>().FirstAsync(expression);
        }

        /// <summary>
        /// 查全部AS Queryable
        /// </summary>
        /// <returns></returns>
        public virtual ISugarQueryable<TEntity> QueryAsQueryable()
        {
            return db.Queryable<TEntity>();
        }

        /// <summary>
        /// 查全部
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> QueryAsync()
        {
            return await db.Queryable<TEntity>().ToListAsync();
        }

        /// <summary>
        /// 查全部并按某个字段排序
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, object>> field)
        {
            return await db.Queryable<TEntity>().OrderBy(field).ToListAsync();
        }

        /// <summary>
        /// 根据条件查多条
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await db.Queryable<TEntity>().Where(expression).ToListAsync();
        }

        /// <summary>
        /// 根据条件查多条并按某字段排序
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public virtual async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> field)
        {
            return await db.Queryable<TEntity>().Where(expression).OrderBy(field).ToListAsync();
        }

        /// <summary>
        /// 是否存在记录
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await db.Queryable<TEntity>().AnyAsync(expression);
        }

        /// <summary>
        /// 异步带条件分页
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="PageSize"></param>
        /// <param name="PageIndex"></param>
        /// <returns></returns>
        public virtual async Task<(List<TEntity>, int)> ToPageListAsync(Expression<Func<TEntity, bool>> expression, int PageSize = 10, int PageIndex = 1)
        {
            RefAsync<int> total = 0;
            var list = await db.Queryable<TEntity>().Where(expression).ToPageListAsync(PageIndex, PageSize, total);
            return (list, total);
        }

        /// <summary>
        /// 异步带条件分页
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="PageSize"></param>
        /// <param name="PageIndex"></param>
        /// <returns></returns>
        public virtual async Task<(List<TEntity>, int)> ToPageListAsync(Expression<Func<TEntity, object>> sort, Expression<Func<TEntity, bool>> expression, int PageSize = 10, int PageIndex = 1)
        {
            RefAsync<int> total = 0;
            var list = await db.Queryable<TEntity>().OrderByDescending(sort).Where(expression).ToPageListAsync(PageIndex, PageSize, total);
            return (list, total);
        }

        /// <summary>
        /// 异步分页
        /// </summary>
        /// <param name="PageSize"></param>
        /// <param name="PageIndex"></param>
        /// <returns></returns>
        public virtual async Task<(List<TEntity>, int)> ToPageListAsync(int PageSize = 10, int PageIndex = 1)
        {
            RefAsync<int> total = 0;
            var list = await db.Queryable<TEntity>().ToPageListAsync(PageIndex, PageSize, total);
            return (list, total);
        }

        /// <summary>
        /// 同步分页
        /// </summary>
        /// <param name="PageSize"></param>
        /// <param name="PageIndex"></param>
        /// <returns></returns>
        public virtual (List<TEntity>, int) ToPageList(int PageSize = 10, int PageIndex = 1)
        {
            int total = 0;
            var list = db.Queryable<TEntity>().ToPageList(PageIndex, PageSize, ref total);
            return (list, total);
        }

        /// <summary>
        /// 同步带条件分页
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="PageSize"></param>
        /// <param name="PageIndex"></param>
        /// <returns></returns>
        public virtual (List<TEntity>, int) ToPageList(Expression<Func<TEntity, bool>> expression, int PageSize = 10, int PageIndex = 1)
        {
            int total = 0;
            var list = db.Queryable<TEntity>().Where(expression).ToPageList(PageIndex, PageSize, ref total);
            return (list, total);
        }

        /// <summary>
        /// 获取Db上下文
        /// </summary>
        /// <returns></returns>
        public ISqlSugarClient GetDbContext()
        {
            return db;
        }
    }


    public class Repository<TEntity, TKey> : Repository<TEntity>,IRepository<TEntity, TKey> 
        where TEntity : class, new()
        where TKey : struct
    {
        private readonly ISqlSugarClient db;

        public Repository(ISqlSugarClient db) : base(db)
        {
            this.db = db;
        }

        /// <summary>
        /// 单条删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> DeleteAsync(TKey key)
        {
            return await db.Deleteable<TEntity>(key).ExecuteCommandAsync();
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<int> ManyDeleteAsync(List<TKey> keys)
        {
            return await db.Deleteable<TEntity>(keys).ExecuteCommandAsync();
        }
       
        /// <summary>
        /// 根据主键查单条
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> FindAsync(TKey key)
        {
            return await db.Queryable<TEntity>().InSingleAsync(key);
        }
    }
}